#include <stdio.h>
#include <pthread.h>
#include <modbus.h>
#include <modbus-tcp.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <sys/types.h>
#include "shmem.h"
#include "msg_queue_peer.h"
#include "cJSON.h"

#define SLAVE_IP "192.168.0.146"
#define SLAVE_PORT 502
// 定义数据点键值
#define AC_MODE_KEY 2001
#define CURTAIN_KEY 2002
#define WINDOW_KEY 2003
#define AD_SCREEN_KEY 2004
#define WATER_CONTROL_KEY 2005
#define AC_POWER_KEY 2006

// 空调模式操作值
#define AC_MODE_COOL 11
#define AC_MODE_HEAT 22
#define AC_MODE_DRY 33
// 消息队列消息结构
struct msgbuf
{
    long mtype;
    char mdata[256];
};

static struct shm_param para;

typedef struct
{
    int key;
    char name[32];
    int type;
    int typeStata;
    int value;
    float floatValue;
} Stm32Data;

typedef struct
{
    int key;
    char name[32];
    int addr;
    int type;
    int typeStata;
    int value;
} ModbusData;

typedef struct
{
    int key;
    char name[32];
    int type;
    int typeStata;
    int addr;
    int value;
} MetaServerData;

typedef struct
{
    Stm32Data stm32_list[8];   // 固定数组，存储stm32数据
    int stm32_count;           // 实际有效数量
    ModbusData modbus_list[6]; // 固定数组，存储modbus数据
    int modbus_count;
    MetaServerData meta_list[7]; // 固定数组，存储metaServer数据
    int meta_count;
} DeviceData;

DeviceData *device = NULL;
union semun
{
    int val;
};

// 释放设备数据内存
void device_data_free(DeviceData *device)
{
    if (device)
    {
        free(device->stm32_list);
        free(device->modbus_list);
        free(device->meta_list);
        free(device);
    }
}

void *data_reader_thread(void *arg)
{
    modbus_t *ctx = (modbus_t *)arg;
    //  创建共享内存
    int ret = shm_init(&para, "main.c", sizeof(DeviceData));
    if (ret < 0)
    {
        perror("shm_init failed");
        device_data_free(device);
        return NULL;
    }

    //  获取共享内存地址
    DeviceData *shm_device = (DeviceData *)shm_getaddr(&para);
    if (!shm_device)
    {
        perror("shm_getaddr failed");
        device_data_free(device);
        return NULL;
    }
    printf("shm_addr ----------- %d\n", shm_device->modbus_list[0].key);

    shm_device->modbus_list[0].value = AC_MODE_COOL;
    modbus_write_register(ctx, 20011, AC_MODE_COOL);
    printf("空调模式已设置为默认值: 制冷模式(%d)\n", AC_MODE_COOL);
    // 创建信号量
    key_t sem_key = ftok("./main.c", 'e');
    int semid = semget(sem_key, 1, IPC_CREAT | 0666);
    if (semid < 0)
    {
        perror("semget err");
        return NULL;
    }

    // 初始化信号量
    union semun sem_val;
    sem_val.val = 1;
    semctl(semid, 0, SETVAL, sem_val);

    while (1)
    {
        // P操作 - 申请信号量
        struct sembuf p_op = {0, -1, 0};
        semop(semid, &p_op, 1);

        // 读取设备数据
        uint16_t temp_value;
        uint8_t temp_bit;

        // 读取空调模式
        if (modbus_read_registers(ctx, 20011, 1, &temp_value) == 1)
        {
            // printf("窗帘寄存器值: %d\n", temp_value);
            shm_device->modbus_list[0].value = temp_value;
        }
        // 读取窗帘位置
        if (modbus_read_registers(ctx, 20021, 1, &temp_value) == 1)
        {
            // printf("窗帘寄存器值: %d\n", temp_value);
            shm_device->modbus_list[1].value = temp_value;
        }

        // 读取窗户状态
        if (modbus_read_bits(ctx, 20031, 1, &temp_bit) == 1)
        {
            shm_device->modbus_list[2].value = temp_bit;
        }

        // 读取广告屏状态
        if (modbus_read_bits(ctx, 20041, 1, &temp_bit) == 1)
        {
            shm_device->modbus_list[3].value = temp_bit;
        }

        if (modbus_read_registers(ctx, 20051, 1, &temp_value))
        {
            shm_device->modbus_list[4].value = temp_value;
        }
        // 读取水量控制
        if (modbus_read_bits(ctx, 20061, 1, &temp_bit) == 1)
        {
            shm_device->modbus_list[5].value = temp_bit;
        }

        printf("数据已更新到共享内存:\n");
        printf("空调模式: %d, 窗帘:%d%%, 窗户: %s,水量：%d%%,广告屏状态：%s,空调电源状态：%s\n",
               shm_device->modbus_list[0].value,
               shm_device->modbus_list[1].value,
               shm_device->modbus_list[2].value ? "开" : "关",
               shm_device->modbus_list[4].value,
               shm_device->modbus_list[3].value ? "开" : "关",
               shm_device->modbus_list[5].value ? "开" : "关");

        // V操作 - 释放信号量
        struct sembuf v_op = {0, 1, 0};
        semop(semid, &v_op, 1);

        sleep(2); // 2秒读取一次
    }
    shmdt(shm_device);
    return NULL;
}
void *control_thread(void *arg)
{
    modbus_t *ctx = (modbus_t *)arg;
    // 连接到信号量
    key_t sem_key = ftok("./main.c", 'e');
    int semid = semget(sem_key, 1, 0666);
    if (semid < 0)
    {
        perror("semget err");
        return NULL;
    }
    while (1)
    {
        struct msgbuf recv_buf;
        // P操作 - 申请信号量
        // struct sembuf p_op = {0, -1, 0};
        // semop(semid, &p_op, 1);
        if (msg_queue_recv("modbus", &recv_buf, sizeof(recv_buf), 0, 0) > 0)
        {
            printf("recv from msga type = %ld\n", recv_buf.mtype);
            printf("recv from msga data = %s\n", recv_buf.mdata);
            // P操作 - 申请信号量
            struct sembuf p_op = {0, -1, 0};
            semop(semid, &p_op, 1);
            cJSON *root = cJSON_Parse(recv_buf.mdata);
            if (NULL == root)
            {
                printf("JSON parse failed:%s\n", cJSON_GetErrorPtr());
                continue;
            }
            // 获取modbus对象
            cJSON *modbus_obj = cJSON_GetObjectItem(root, "modbus");
            if (NULL == modbus_obj)
            {
                printf("NO modbus object found\n");
                cJSON_Delete(root);
                continue;
            }
            // 遍历所有modbus设备配置
            // 解析各个字段
            cJSON *key_obj = cJSON_GetObjectItem(modbus_obj, "key");
            cJSON *name_obj = cJSON_GetObjectItem(modbus_obj, "name");
            cJSON *addr_obj = cJSON_GetObjectItem(modbus_obj, "addr");
            cJSON *type_obj = cJSON_GetObjectItem(modbus_obj, "type");
            cJSON *value_obj = cJSON_GetObjectItem(modbus_obj, "value");
            cJSON *typeStata_obj = cJSON_GetObjectItem(modbus_obj, "typeStata");
            // 检查必要字段是否存在
            if (key_obj && addr_obj && value_obj)
            {
                int key = key_obj ? key_obj->valueint : -1;
                const char *name = name_obj ? name_obj->valuestring : "Unknown";
                int addr = addr_obj->valueint;
                int type = type_obj ? type_obj->valueint : 0;
                int value = value_obj->valueint;
                int typeStata = typeStata_obj ? typeStata_obj->valueint : 0;

                printf("Modbus Control - Key:%d, Name:%s, Addr:%d, Type:%d, Value:%d, TypeStata:%d\n",
                       key, name, addr, type, value, typeStata);
                // 根据消息类型执行控制操作
                switch (key)
                {
                case AC_MODE_KEY:
                    if (value == AC_MODE_COOL || value == AC_MODE_HEAT || value == AC_MODE_DRY)
                    {
                        modbus_write_register(ctx, addr, value);
                        printf("设置空调模式：%d\n", value);
                    }
                    break;
                case CURTAIN_KEY:
                    if (value >= 0 && value <= 100)
                    {
                        modbus_write_register(ctx, addr, value);
                        printf("设置窗帘位置: %d%%\n", value);
                    }
                    break;
                case WINDOW_KEY:
                    modbus_write_bit(ctx, addr, value);
                    printf("设置窗户状态: %s\n", value ? "开" : "关");
                    break;

                case AD_SCREEN_KEY:
                    modbus_write_bit(ctx, addr, value);
                    printf("设置广告屏状态: %s\n", value ? "开" : "关");
                    break;

                case WATER_CONTROL_KEY:
                    if (value >= 0 && value <= 100)
                    {
                        modbus_write_register(ctx, addr, value);
                        printf("设置水量控制: %d%%\n", value);
                    }
                    break;

                case AC_POWER_KEY:
                    modbus_write_bit(ctx, addr, value);
                    printf("设置空调电源: %s\n", value ? "开" : "关");
                    break;

                default:
                    printf("未知的控制命令: %d\n", key);
                    break;
                }
                // V操作 - 释放信号量
                struct sembuf v_op = {0, 1, 0};
                semop(semid, &v_op, 1);
            }
            // 释放JSON内存
            cJSON_Delete(root);
        }
    }
    usleep(100000); // 100ms检查一次消息

    return NULL;
}
int main(int argc, char const *argv[])
{
    // 创建Modbus TCP实例
    modbus_t *ctx = modbus_new_tcp(SLAVE_IP, SLAVE_PORT);
    if (ctx == NULL)
    {
        fprintf(stderr, "Unable to allocate libmodbus context\n");
        return -1;
    }

    // 设置从机id
    int slave = 1;
    if (modbus_set_slave(ctx, slave))
    {
        printf("slave err\n");
        modbus_free(ctx);
        return -1;
    }

    // 链接
    if (modbus_connect(ctx))
    {
        printf("connect err: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }

    printf("Modbus connected successfully\n");

    // 创建线程
    pthread_t tid_reader, tid_control;

    if (pthread_create(&tid_reader, NULL, data_reader_thread, ctx))
    {
        printf("创建数据读取线程失败\n");
        modbus_close(ctx);
        modbus_free(ctx);
        return -1;
    }
    sleep(1);
    if (pthread_create(&tid_control, NULL, control_thread, ctx))
    {
        printf("创建控制线程失败\n");
        modbus_close(ctx);
        modbus_free(ctx);
        return -1;
    }

    pthread_join(tid_reader, NULL);
    pthread_join(tid_control, NULL);

    modbus_close(ctx);
    modbus_free(ctx);

    return 0;
}
